package com.unknowpupil.web.component.aspect;

import com.jpay.ext.kit.IpKit;
import com.unknowpupil.web.component.annotation.log.SysLog;
import com.unknowpupil.web.config.dto.LogRecord;
import com.unknowpupil.web.utils.MapperUtils;
import com.unknowpupil.web.utils.SafeTools;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Map;

import static com.unknowpupil.web.utils.GetAddressByIp.GetAddressByIp;

/**
 * @Classname: LogRecord
 * @Author: <a> w10g </a>
 * @CreateDate: Create in 2019/10/8 13:58
 * @Description:
 * @Version: 1.0
 */
@Aspect
@Component
public class WebLogAspect {
    /**
     *    定义成static final,logger变量不可变，读取速度快
     */
    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
    private Long startTime;

    private LogRecord syslog;

    /**
     *    //切入点描述 这个是controller包的切入点
     *     @Pointcut("execution(public * com.unknowpupil.web.controller..*.*(..))")
     *
     *     下面是重写日志收集希望存入数据库，TODO：最好是noSql 后续插入数据库-> MongoDB
     */
    @Pointcut("@annotation(com.unknowpupil.web.component.annotation.log.SysLog)")
    public void webLog(){

    }

    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint){
        startTime = System.currentTimeMillis();
        syslog = new LogRecord();
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpSession session = (HttpSession) attributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
        syslog.setClassMethod(joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
        syslog.setHttpMethod(request.getMethod());
        //获取传入目标方法的参数
        Object [] args = joinPoint.getArgs();
        for (int i=0;i<args.length;i++){
            Object o = args[i];
            if(o instanceof ServletRequest||o instanceof ServletResponse || o instanceof MultipartFile){
                args[i] = o.toString();
            }
        }
        String str="";
        try{
            str = MapperUtils.obj2json(args);
            syslog.setParams(str.length()>5000?MapperUtils.obj2json("请求参数数据过长不与显示"):str);
        }catch (Exception e){
            e.printStackTrace();
        }
        //微信支付调用转换ip
        String realIp = IpKit.getRealIp(request);

        String ip = SafeTools.getClientIp(request);
        if("0.0.0.0".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip) || "localhost".equals(ip) || "127.0.0.1".equals(ip)){
            ip = "127.0.0.1";
        }
        /**
         * 调用淘宝api获取ip地址归属
         */
        GetAddressByIp(ip);

        syslog.setRemoteAddr(realIp);
        syslog.setRequestUri(request.getRequestURL().toString());
        if(session != null){
            syslog.setSessionId(session.getId());
        }
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLog myLog = method.getAnnotation(SysLog.class);
        if(myLog != null){
            //注解上的描述
            syslog.setTitle(myLog.value());
        }
        Map<String,String> browserMap = SafeTools.getOsAndBrowserInfo(request);
        syslog.setBrowser(browserMap.get("os")+"-"+browserMap.get("browser"));


        syslog.setType(SafeTools.isAjax(request)?"Ajax请求":"普通请求");
        // TODO:那个用户访问
        ////        if(ShiroUtils.getUser() != null) {
        ////            syslog.setUsername(StringUtils.isNotBlank(ShiroUtils.getUser().getLoginName()) ? ShiroUtils.getUser().getLoginName() : ShiroUtils.getUser().getLoginName());
        ////        }
        //        //TODO:可打印访问信息
        logger.info(syslog.toString());
    }

    @Around("webLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            Object obj = proceedingJoinPoint.proceed();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            logger.warn("错误{}",e.getMessage());
            syslog.setException(e.getMessage());
            throw e;
        }
    }

    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) {
        //TODO:获取用户
        /**
         * //        if(ShiroUtils.getUser() != null) {
         * //            syslog.setUsername(StringUtils.isNotBlank(ShiroUtils.getUser().getLoginName()) ? ShiroUtils.getUser().getLoginName() : ShiroUtils.getUser().getLoginName());
         * //        }
         */
        try {
            String retString = MapperUtils.obj2json(ret);
            syslog.setResponse(retString.length()>5000?MapperUtils.obj2json("请求参数数据过长不与显示"):retString);
            syslog.setUseTime(System.currentTimeMillis() - startTime);

            logger.info("请求返回内容:{}", retString);
            logger.info("请求结束时间:{}", System.currentTimeMillis());
            logger.info("请求总耗时:{}毫秒", System.currentTimeMillis() - startTime);
            // TODO:插入数据库
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
